/**
 * 
 */
package model;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Observable;

/**
 * @author Michael & Pierre
 *
 */
/**
 * Model used to manage the local user and the remote users
 */
public class Users extends Observable {
	
	private String localUsername;
	private User localUser;
	private ArrayList<User> connectedUsers;
	
	private boolean busy = false;
	
	public Users() {
		connectedUsers = new ArrayList<User>();
	}
	
	/**
	 * 
	 * @param u username of the local user
	 */
	public void setLocalUsername(String u) {
		localUsername = u;
	}
	
	public String getLocalUsername() {
		return localUsername;
	}
	
	/**
	 * 
	 * @param username username of the local user
	 */
	public void setLocalUser(String username) {
		try {
			
			localUser = new User(username, InetAddress.getLocalHost().getHostName());
			setChanged();
			notifyObservers(localUser);
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Method used to add a user in the connected users list
	 * @param username username of the new user
	 * @param host hostname of the device of the new user
	 */
	public void addUser(String username, String host) { 
		User newUser;
		try {
			newUser = this.getUser(username, host);
		} catch (UserException e) {
			newUser = new User(username, host);
		}
		
		if (!connectedUsers.contains(newUser) 
			&& !((newUser.getUsername().equals(localUser.getUsername())) && (newUser.getHost().equals(localUser.getHost())))) {		
			connectedUsers.add(newUser);
			setChanged();
			notifyObservers(newUser);
		}
	}
	
	/**
	 * Used to remove a user from the connected users list
	 * @param u user which will be remove
	 */
	public void removeUser(User u) {
		connectedUsers.remove(u);
		setChanged();
		notifyObservers(u);
	}
	
	public String toString(){
		return connectedUsers.toString();
	}
	
	/**
	 * 
	 * @return localUser
	 */
	public User getLocalUser() {
		return localUser;
	}
	
	/**
	 * Return a user from the connected users list
	 * @param nameAndHost name'at'host of the user
	 * @return the user if he has been found
	 * @throws UserException
	 */
	public User getUser(String nameAndHost) throws UserException { 
		for (User u : connectedUsers) {
			if (u.toString().equals(nameAndHost)) {
				return u;
			}
		}
		throw new UserException("No such connected user");
	}
	
	/**
	 * Return a user from the connected users list
	 * @param username username of the user 
	 * @param host hostname of the device of the user
	 * @return the user if he has been found
	 * @throws UserException
	 */
	public User getUser(String username, String host) throws UserException {
		for (User u : connectedUsers) {
			if (u.getUsername().equals(username) && u.getHost().equals(host)) {
				return u;
			}
		}
		throw new UserException("No such connected user");
	}
	
	/**
	 * Called before a class read or write the connected users list
	 * @throws InterruptedException
	 */
	public synchronized void checkIn() throws InterruptedException { // should be called before modify connectedUsers
		while (busy) {
			wait();
		}
		busy = true;
	}
	
	/**
	 * Called after a class read or write the connected users list
	 */
	public synchronized void checkOut() { // should be called after modify connectedUsers
		busy = false;
		notifyAll();
	}
}
